﻿using System;

namespace PCE.Domain
{
	public abstract class Entity<TKey>
		where TKey : IEquatable<TKey>
	{
		public virtual TKey Id { get; protected set; }

		private static bool IsTransient(Entity<TKey> obj)
		{
			return obj != null && Equals(obj.Id, default(TKey));
		}

		private Type GetUnproxiedType()
		{
			return GetType();
		}

		public override bool Equals(object obj)
		{
			return Equals(obj as Entity<TKey>);
		}

		public virtual bool Equals(Entity<TKey> other)
		{
			if (other == null)
				return false;
			if (ReferenceEquals(this, other))
				return true;
			if (!IsTransient(this) &&
				!IsTransient(other) &&
				Equals(Id, other.Id))
			{
				var otherType = other.GetUnproxiedType();
				var thisType = GetUnproxiedType();
				return thisType.IsAssignableFrom(otherType) || otherType.IsAssignableFrom(thisType);
			}
			return false;
		}

		public override int GetHashCode()
		{
			if (Equals(Id, default(TKey)))
				return base.GetHashCode();
			return Id.GetHashCode();
		}
	}
}